home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
The Original Shareware 1.1
/
The Original Shareware (WeMake CDs)(Volume 1.1)(CDs, Inc)(1993).iso
/
16
/
xmodemc.zip
/
XMODEM.C
next >
Wrap
C/C++ Source or Header
|
1986-12-17
|
9KB
|
374 lines
/* xmodem.c copyright 1986 Maple Lawn Farm, Inc.
* exit: 0 if successful, -1 for failure, compile with mlfcu.c:
* cc -i -O -s -DCU mlfcu.c xmodem.c -o cu or with xr.c:
* cc -i -O -s xr.c xmodem.c -o xr, ln xr xt */
#include <signal.h>
#include <stdio.h>
#ifdef CU
extern int rlfd; /* the open line in cu */
#define WFD rlfd
#define RFD rlfd
#define errf stderr
#else
extern FILE *errf; /* error file for remote */
#define WFD 1 /* stdout */
#define RFD 0 /* stdin */
#endif
#define BSIZE 128
#define DEBUG 01
#define LF 02
#define CRC 04
#define NOREAD(x, c) (rchar(x, &c) == -1)
#define TX(c) write(WFD, &c, 1)
#define ever (;;)
static char soh = 0x01,
eot = 0x04,
ack = 0x06,
nak = 0x15,
can = 0x18,
crcinit = 'C',
cksum;
static int debug,
crc;
int kleenex(),
onalarm();
unsigned crcsum;
xget(fp, opts)
FILE *fp;
int opts;
{
char buf[BSIZE],
b = 1,
inch,
crchi;
int iput = BSIZE;
register i;
debug = (opts & DEBUG);
crc = (opts & CRC);
signal(SIGALRM, onalarm);
#ifdef CU
signal(SIGINT, kleenex);
#else
sleep(10);
#endif
(crc) ? TX(crcinit) : TX(nak);
for ever {
if NOREAD(10, inch) {
err("Timeout during SOH");
cksend(crc ? crcinit : nak) ;
continue;
}
if (inch == eot)
break;
if (inch == can) {
err("CAN block %u", b);
kleenex(-1);
}
if (inch != soh) {
err("Bad SOH block %u: %#x", b, (inch & 0xff));
cksend(nak);
continue;
}
if NOREAD(2, inch) {
err("Timeout block %u during blocknum", b);
cksend(nak);
continue;
}
if ((inch & 0xff) != b) {
err("Expected blocknum %u, got %u", b, (inch & 0xff));
cksend(nak);
continue;
}
if NOREAD(2, inch) {
err("Timeout block %u during ~blocknum", b);
cksend(nak);
continue;
}
if ((inch & 0xff) != (~b & 0xff)) {
err("Expected ~blocknum %u, got %u",
(~b & 0xff), (inch & 0xff));
cksend(nak);
continue;
}
/* Read in 128 byte block without taking time for checksums or crc. */
for (i = 0; i < BSIZE; i++)
if NOREAD(2, buf[i])
break;
if (i < BSIZE) {
err("Timeout data recv, char #%d", i);
cksend(nak);
continue;
}
if (crc) {
if NOREAD(2, crchi) {
err("Timeout crc hibyte");
cksend(nak);
continue;
}
crchi &= 0xff;
}
if NOREAD(2, inch) {
err("Timeout %s", (crc) ? "crc lobyte" : "checksum");
cksend(nak);
continue;
}
/* Now, when we have the whole packet, do the checksum or crc. */
for (cksum = 0, crcsum = 0, i = 0; i < BSIZE; i++)
upsum(buf[i]);
if (crc) {
upsum(0); /* needed for crcsum */
upsum(0);
if ((inch & 0xff) + (crchi << 8) != crcsum) {
err("Expected crc %u, got %u",
crcsum, (inch & 0xff) + (crchi << 8));
cksend(nak);
continue;
}
}
else {
cksum %= 256;
if (cksum != (inch & 0xff)) {
err("Expected checksum %u, got %u",
cksum, (inch & 0xff));
cksend(nak);
continue;
}
}
TX(ack);
#ifdef CU
putc('.', stderr);
#endif
if (opts & LF)
for (i=0, iput=0; i < BSIZE; i++) {
if (buf[i] == 0x1a) /* old ms-dos eof */
break;
if (buf[i] != '\r')
buf[iput++] = buf[i];
}
fwrite(buf, iput, 1, fp);
b++;
b %= 256;
}
TX(ack);
kleenex(0);
}
xput(fp, opts)
FILE *fp;
int opts;
{
register i;
char buf[BSIZE],
b = 1,
cb,
crclo,
inch;
int cread;
#ifdef CU
signal(SIGINT, kleenex);
#endif
signal(SIGALRM, onalarm);
debug = (opts & DEBUG);
rchar(60, &cb);
if (cb == crcinit)
crc = 1;
else if (cb == nak)
crc = 0;
else {
err("No startup %s", (crc) ? "'C'" : "NAK");
kleenex(-1);
}
cread = fillbuf(fp, buf, (opts & LF));
while (cread) {
for (i = cread; i < BSIZE; i++)
buf[i] = 0;
TX(soh);
TX(b);
cb = (~b & 0xff);
TX(cb);
write(WFD, buf, BSIZE);
for (cksum = 0, crcsum = 0, i = 0; i < BSIZE; i++)
upsum (buf[i]);
if (crc) {
upsum(0); /* needed for crcsum */
upsum(0);
crclo = crcsum;
cb = (crcsum >> 8);
TX(cb);
TX(crclo);
}
else {
cksum %= 256;
TX(cksum);
}
if NOREAD(15, inch) {
err("Timeout after block %u", b);
continue;
}
if (inch == can) {
err("CAN after block %u", b);
kleenex(-1);
}
if (inch != ack) {
err("Non-ACK after block %u: %#x", b, inch);
continue;
}
#ifdef CU
putc('.', stderr);
#else
if (debug)
fprintf(errf, "Validated block %u\n", b);
#endif
cread = fillbuf(fp, buf, (opts & LF));
b++;
b %= 256;
}
for ever {
TX(eot);
if NOREAD(15, inch) {
err("Timeout during EOT");
continue;
}
if (inch == can) {
err("CAN during EOT");
kleenex(-1);
}
if (inch != ack) {
err("Non-ACK during EOT: %#x", inch);
continue;
}
break;
}
kleenex(0);
}
fillbuf(fp, buf, lf)
FILE *fp;
char *buf;
int lf;
{
int i = 0, c;
static int cr_held;
if (cr_held) {
buf[i] = '\n';
i++;
cr_held--;
}
for (; i < BSIZE; i++) {
if ((c = getc(fp)) == EOF)
break;
if (c == '\n' && lf) {
buf[i] = '\r';
if (i == 127) {
cr_held++;
return BSIZE;
}
buf[i+1] = '\n';
i++;
}
else
buf[i] = c;
}
return i;
}
upsum(c)
char c;
{
register unsigned shift;
register unsigned flag;
if (crc)
for (shift = 0x80; shift; shift >>= 1) {
flag = (crcsum & 0x8000);
crcsum <<= 1;
crcsum |= ((shift & c) ? 1 : 0);
if (flag)
crcsum ^= 0x1021;
}
else
cksum += c;
}
/* Timeout in rchar() works by deliberately interrupting the read()
* system call. errno=EINTR, so no reason for a perror() autopsy. */
rchar(timeout, cp)
unsigned timeout;
char *cp;
{
int c;
alarm(timeout);
if ((c = read(RFD, cp, 1)) == -1)
return -1;
alarm(0);
return c;
}
onalarm()
{
signal(SIGALRM, onalarm);
}
kleenex(sig)
int sig;
{
#ifdef CU
if (sig > 0)
cksend(can);
else
fprintf(stderr, "\r\nFile transfer %s.",
(sig) ? "cancelled" : "complete");
fprintf(stderr, "\r\n");
#else
printf("File transfer %s.\r\n", (sig) ? "cancelled" : "complete");
resetline();
#endif
exit(sig);
}
cksend(ch)
char ch;
{
int j;
char cp;
do {
j = rchar(2, &cp);
} while (j != -1);
TX(ch);
}
/* VARARGS1 */
err(s, i, j)
char *s;
int i, j;
{
if (debug) {
fprintf(errf, s, i, j);
#ifndef CU
fprintf(errf, "\n");
}
#else
fprintf(errf, "\r\n");
}
else
putc('%', stderr);
#endif
}